package com.kmxd.ams.app.system;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.lang.tree.Tree;
import cn.hutool.core.lang.tree.TreeNode;
import cn.hutool.core.lang.tree.TreeUtil;
import cn.hutool.core.util.NumberUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.extra.spring.SpringUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.kmxd.ams.client.system.ISysDeptSvc;
import com.kmxd.ams.client.system.dto.SysDeptAddDTO;
import com.kmxd.ams.client.system.dto.SysDeptEditDTO;
import com.kmxd.ams.client.system.dto.SysDeptQueryDTO;
import com.kmxd.ams.client.system.vo.SysDeptListVO;
import com.kmxd.ams.client.system.vo.SysDeptVO;
import com.kmxd.ams.core.common.constant.CacheConst;
import com.kmxd.ams.core.common.constant.ErrorCode;
import com.kmxd.ams.core.common.enums.StatusEnum;
import com.kmxd.ams.core.common.query.QueryGen;
import com.kmxd.ams.core.exception.BizTipException;
import com.kmxd.ams.core.util.IdUtil;
import com.kmxd.ams.core.util.SecurityUtil;
import com.kmxd.ams.infra.system.entity.SysDept;
import com.kmxd.ams.infra.system.entity.SysUser;
import com.kmxd.ams.infra.system.mapper.SysDeptMapper;
import com.kmxd.ams.infra.system.mapper.SysUserMapper;
import java.util.*;
import java.util.stream.Collectors;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.compress.utils.Lists;
import org.springframework.cache.annotation.CacheConfig;
import org.springframework.cache.annotation.CacheEvict;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;

/**
 * 部门表 服务实现类
 *
 * @author admin
 * @since 2021-06-10
 */
@Service
@Slf4j
@AllArgsConstructor
@CacheConfig(cacheNames = CacheConst.CACHE_PREFIX_SYS_DEPT)
public class SysDeptSvcImpl extends ServiceImpl<SysDeptMapper, SysDept> implements ISysDeptSvc {

  private SysDeptMapper sysDeptMapper;
  private SysUserMapper sysUserMapper;

  @Cacheable(keyGenerator = "myKeyGenerator")
  @Override
  public Page<SysDeptListVO> selectPage(Page reqPage, SysDeptQueryDTO req) {
    req.setComId(ObjectUtil.isEmpty(req.getComId()) ? SecurityUtil.getCropId() : req.getComId());
    LambdaQueryWrapper<SysDept> queryWrapper =
        QueryGen.init(new QueryWrapper<SysDept>(), req).lambda();
    queryWrapper.orderByAsc(SysDept::getSort);
    Page<SysDept> page = sysDeptMapper.selectPage(reqPage, queryWrapper);
    Page<SysDeptListVO> voPage = BeanUtil.copyProperties(page, Page.class);
    voPage.setRecords(BeanUtil.copyToList(page.getRecords(), SysDeptListVO.class));
    return voPage;
  }

  @Cacheable(keyGenerator = "myKeyGenerator")
  @Override
  public List<SysDeptListVO> selectList(SysDeptQueryDTO req) {
    req.setComId(ObjectUtil.isEmpty(req.getComId()) ? SecurityUtil.getCropId() : req.getComId());
    LambdaQueryWrapper<SysDept> queryWrapper =
        QueryGen.init(new QueryWrapper<SysDept>(), req).lambda();
    queryWrapper.orderByAsc(SysDept::getSort);
    List<SysDept> list = sysDeptMapper.selectList(queryWrapper);
    return BeanUtil.copyToList(list, SysDeptListVO.class);
  }

  @Cacheable(keyGenerator = "myKeyGenerator")
  @Override
  public List<SysDeptListVO> listAll() {
    LambdaQueryWrapper<SysDept> queryWrapper = Wrappers.lambdaQuery();
    List<SysDept> list = sysDeptMapper.selectList(queryWrapper);
    return BeanUtil.copyToList(list, SysDeptListVO.class);
  }

  @CacheEvict(allEntries = true)
  @Override
  @Transactional(rollbackFor = Exception.class)
  public void add(SysDeptAddDTO req) {
    if (!this.checkUniqueDeptCode(req.getCode(), null)) {
      throw BizTipException.instance(ErrorCode.VALIDATE_ERROR, "部门编码已存在！");
    }
    SysDept entity = BeanUtil.copyProperties(req, SysDept.class);
    entity.setComId(
        ObjectUtil.isNotEmpty(req.getComId()) ? req.getComId() : SecurityUtil.getCropId());
    if (Objects.isNull(req.getParentId())) {
      entity.setParentId(0L);
      entity.setPathCode(entity.getParentId().toString());
    } else {
      SysDept parent = sysDeptMapper.selectById(req.getParentId());
      entity.setPathCode(parent.getPathCode() + "," + entity.getParentId().toString());
    }
    sysDeptMapper.insert(entity);
  }

  @CacheEvict(allEntries = true)
  @Override
  @Transactional(rollbackFor = Exception.class)
  public void edit(SysDeptEditDTO req) {
    List<SysDeptListVO> listAll = listAll();
    List<SysDeptListVO> datas = Lists.newArrayList();
    getFindInSet(datas, listAll, req.getId());
    List<SysDeptListVO> statusYes =
        datas.stream()
            .filter(x -> ObjectUtil.equal(x.getStatus(), StatusEnum.YES.getCode()))
            .collect(Collectors.toList());

    if (req.getStatus().equals(StatusEnum.NO.getCode()) && statusYes.size() > 0) {
      throw BizTipException.instance(ErrorCode.VALIDATE_ERROR, "该部门存在未停用的下级部门");
    }
    SysDept entity = BeanUtil.copyProperties(req, SysDept.class);
    if (Objects.isNull(req.getParentId())) {
      entity.setParentId(0L);
      entity.setPathCode(entity.getParentId().toString());
    } else {
      SysDept parent = sysDeptMapper.selectById(req.getParentId());
      entity.setPathCode(parent.getPathCode() + "," + entity.getParentId().toString());
    }
    SysDept sysDept = sysDeptMapper.selectById(req.getId());

    if (!sysDept.getCode().equalsIgnoreCase(req.getCode())) {
      if (!this.checkUniqueDeptCode(req.getCode(), null)) {
        throw BizTipException.instance(ErrorCode.VALIDATE_ERROR, "部门编码已存在！");
      }
    }

    sysDeptMapper.updateById(entity);
    // 启用该部门，则启用该部门的所有上级部门
    List<String> parentList = Arrays.asList(entity.getPathCode().split(","));
    parentList.stream()
        .forEach(
            item -> {
              SysDept sysDeptTemp = new SysDept();
              sysDeptTemp.setId(Long.parseLong(item));
              sysDeptTemp.setStatus(StatusEnum.YES.getCode());
              sysDeptMapper.updateById(sysDeptTemp);
            });
  }

  /**
   * 递归查找当前部门及子部门
   *
   * @param datas
   * @param listAll
   * @param id
   */
  public void getFindInSet(List<SysDeptListVO> datas, List<SysDeptListVO> listAll, Long id) {
    listAll.forEach(
        item -> {
          if (ObjectUtil.equal(id, item.getId())) {
            datas.add(item);
          } else if (ObjectUtil.equal(id, item.getParentId())) {
            datas.add(item);
            getFindInSet(datas, listAll, item.getId());
          }
        });
  }

  @CacheEvict(allEntries = true)
  @Override
  @Transactional(rollbackFor = Exception.class)
  public void remove(String ids) {
    Set<Long> idList = IdUtil.split(ids);
    idList.forEach(
        item -> {
          SysDept sysDept = sysDeptMapper.selectById(item);
          SysDept sysDeptChild =
              sysDeptMapper.selectOne(
                  Wrappers.lambdaQuery(SysDept.class).eq(SysDept::getParentId, item));
          if (Objects.nonNull(sysDeptChild)) {
            throw BizTipException.instance(
                ErrorCode.VALIDATE_ERROR, String.format("部门【%s】存在下级部门，无法删除", sysDept.getName()));
          }
          List<SysUser> lists =
              sysUserMapper.selectList(
                  Wrappers.lambdaQuery(SysUser.class).in(SysUser::getDeptId, item));
          if (lists.size() > 0) {
            throw BizTipException.instance(
                ErrorCode.VALIDATE_ERROR, String.format("部门【%s】存在用户，无法删除", sysDept.getName()));
          }
          sysDeptMapper.deleteById(item);
        });
  }

  @Cacheable(keyGenerator = "myKeyGenerator")
  @Override
  public SysDeptVO view(Long id) {
    SysDept entity = sysDeptMapper.selectById(id);
    return BeanUtil.copyProperties(entity, SysDeptVO.class);
  }

  @Override
  public List<Tree<String>> listDeptTree(Long cropId) {
    ISysDeptSvc sysDeptSvc = SpringUtil.getBean(ISysDeptSvc.class);
    List<SysDeptListVO> sysDeptList = sysDeptSvc.listAll();
    List treeNodeList =
        sysDeptList.stream()
            .filter(
                x ->
                    ObjectUtil.equals(
                        x.getComId(),
                        ObjectUtil.isNotEmpty(cropId) ? cropId : SecurityUtil.getCropId()))
            .map(
                item -> {
                  TreeNode treeNode = new TreeNode();
                  treeNode.setId(item.getId().toString());
                  treeNode.setName(item.getName());
                  treeNode.setParentId(item.getParentId().toString());
                  treeNode.setWeight(item.getSort());
                  return treeNode;
                })
            .collect(Collectors.toList());
    List<Tree<String>> treeList = TreeUtil.build(treeNodeList, "0");
    return CollectionUtils.isEmpty(treeList) ? new ArrayList() : treeList;
  }

  @Override
  public List<Tree<String>> selectDeptTreeAndExcludeNode(String nodeId) {
    ISysDeptSvc sysDeptSvc = SpringUtil.getBean(ISysDeptSvc.class);
    List<SysDeptListVO> sysDeptList = sysDeptSvc.listAll();
    List treeNodeList =
        sysDeptList.stream()
            .filter(x -> ObjectUtil.equals(x.getComId(), SecurityUtil.getCropId()))
            .map(
                item -> {
                  TreeNode treeNode = new TreeNode();
                  treeNode.setId(item.getId().toString());
                  treeNode.setName(item.getName());
                  treeNode.setParentId(item.getParentId().toString());
                  treeNode.setWeight(item.getSort());
                  return treeNode;
                })
            .collect(Collectors.toList());
    List<Tree<String>> treeList = TreeUtil.build(treeNodeList, "0");
    return CollectionUtils.isEmpty(treeList) ? new ArrayList() : treeList;
  }

  @Override
  public List<Tree<String>> selectDeptTree() {
    ISysDeptSvc sysDeptSvc = SpringUtil.getBean(ISysDeptSvc.class);
    List<SysDeptListVO> sysDeptList = sysDeptSvc.listAll();
    List treeNodeList =
        sysDeptList.stream()
            .filter(x -> ObjectUtil.equals(x.getComId(), SecurityUtil.getCropId()))
            .map(
                item -> {
                  TreeNode treeNode = new TreeNode();
                  treeNode.setId(item.getId().toString());
                  treeNode.setName(item.getName());
                  treeNode.setParentId(item.getParentId().toString());
                  treeNode.setWeight(item.getSort());
                  return treeNode;
                })
            .collect(Collectors.toList());
    List<Tree<String>> treeList = TreeUtil.build(treeNodeList, "0");
    return CollectionUtils.isEmpty(treeList) ? new ArrayList() : treeList;
  }

  private Boolean checkUniqueDeptCode(String value, Long id) {
    if (StrUtil.isBlank(value)) {
      return true;
    }
    id = Objects.isNull(id) ? -1L : id;
    SysDept entity =
        sysDeptMapper.selectOne(Wrappers.lambdaQuery(SysDept.class).eq(SysDept::getCode, value));
    return Objects.isNull(entity) || NumberUtil.equals(entity.getId(), id);
  }

  @CacheEvict(allEntries = true)
  @Override
  public void clearAllCache() {
    log.info("清除系统缓存");
  }
}
